package org.xlp.reflect;

import org.xlp.assertion.AssertUtils;
import org.xlp.utils.XLPStringUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Description: 提供简化反射操作工具类
 * <br/>date: 2024/5/6 22:47
 *
 * @version 1.0
 * @author: xlp
 */
public class ReflectUtils {
    /**
     * 判断指定的类是否存在
     * @param className 要判断的类名
     * @param classLoader 类加载器，该参数为null，则用加载该类的类加载器
     * @return 假如第一个参数为空或指定的类不存在，返回false，否则返回true
     */
    public static boolean hasClass(String className, ClassLoader classLoader){
        if (XLPStringUtil.isEmpty(className)) return false;
        if (classLoader == null){
            classLoader = ReflectUtils.class.getClassLoader();
        }
        try {
            Class.forName(className, false, classLoader);
            return true;
        } catch (ClassNotFoundException ignored) {
        }
        return false;
    }

    /**
     * 判断指定的类是否存在
     * @param className 要判断的类名
     * @return 假如第一个参数为空或指定的类不存在，返回false，否则返回true
     */
    public static boolean hasClass(String className){
        return hasClass(className, null);
    }

    /**
     * 使用反射创建指定类的实例对象
     * @param cs 类
     * @param <T>
     * @return 假如参数为null，返回null，否则返回给定类的实例
     * @throws RuntimeException 假如实例创建失败则抛出该异常
     */
    public static <T> T quickNewInstance(Class<T> cs){
        if(cs == null) return null;
        try {
            return cs.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 使用反射创建指定类的实例对象
     * @param cs 类
     * @param <T>
     * @return 假如参数为null或实例化失败，返回null，否则返回给定类的实例
     */
    public static <T> T newInstance(Class<T> cs){
        if(cs == null) return null;
        try {
            return cs.newInstance();
        } catch (InstantiationException | IllegalAccessException ignored) {}
        return null;
    }

    /**
     * 使用构造函器反射创建该实例
     * @param constructor 构造器
     * @param parameters 参数列表
     * @param <T>
     * @return 假如第一个参数为null，返回null，否则返回实例
     * @throws RuntimeException 假如实例创建失败则抛出该异常
     */
    public static <T> T quickNewInstance(Constructor<T> constructor, Object... parameters){
        if (constructor == null) return null;
        try {
            return constructor.newInstance(parameters);
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e.getTargetException());
        }
    }

    /**
     * 使用构造函器反射创建该实例
     * @param constructor 构造器
     * @param parameters 参数列表
     * @param <T>
     * @return 假如第一个参数为null或实例失败，返回null，否则返回实例
     */
    public static <T> T newInstance(Constructor<T> constructor, Object... parameters){
        if (constructor == null) return null;
        try {
            return constructor.newInstance(parameters);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException ignored) {
        }
        return null;
    }

    /**
     * 执行给定的函数
     * @param method 函数
     * @param ob 对象
     * @param parameters 函数参数
     * @return 给定对象函数返回值
     * @throws NullPointerException 假如第一个或第二个参数为null，则抛出该异常
     * @throws RuntimeException 假如执行失败，则返回该异常
     */
    public static Object quickInvokeMethod(Method method, Object ob, Object... parameters){
        AssertUtils.isNotNull(method, "method parameter must be not null!");
        AssertUtils.isNotNull(ob, "ob parameter must be not null!");
        try {
            return method.invoke(ob, parameters);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e.getTargetException());
        }
    }

    /**
     * 执行给定的函数
     * @param method 函数
     * @param ob 对象
     * @param parameters 函数参数
     * @return 给定对象函数返回值，如果执行失败返回null
     * @throws NullPointerException 假如第一个或第二个参数为null，则抛出该异常
     */
    public static Object invokeMethod(Method method, Object ob, Object... parameters){
        AssertUtils.isNotNull(method, "method parameter must be not null!");
        AssertUtils.isNotNull(ob, "ob parameter must be not null!");
        try {
            return method.invoke(ob, parameters);
        } catch (IllegalAccessException | InvocationTargetException ignored) {
        }
        return null;
    }

    /**
     * 获取指定类的给定名称及参数类型的方法
     * @param cs 类型
     * @param methodName 方法名称
     * @param parameterClasses 方法参数类型
     * @return 返回指定类的给定名称及参数类型的方法
     * @throws NullPointerException 假如第一个为null或第二个参数为空，则抛出该异常
     * @throws RuntimeException 获取方法失败，则抛出该异常
     */
    public static Method quickGetMethod(Class<?> cs, String methodName, Class<?>... parameterClasses){
        AssertUtils.isNotNull(cs, "cs parameter must be not null!");
        AssertUtils.isNotNull(methodName, "methodName parameter must be not null or empty!");
        try {
            return cs.getMethod(methodName, parameterClasses);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取指定类的给定名称及参数类型的方法
     * @param cs 类型
     * @param methodName 方法名称
     * @param parameterClasses 方法参数类型
     * @return 返回指定类的给定名称及参数类型的方法，如果获取失败，则返回null
     * @throws NullPointerException 假如第一个为null或第二个参数为空，则抛出该异常
     */
    public static Method getMethod(Class<?> cs, String methodName, Class<?>... parameterClasses){
        AssertUtils.isNotNull(cs, "cs parameter must be not null!");
        AssertUtils.isNotNull(methodName, "methodName parameter must be not null or empty!");
        try {
            return cs.getMethod(methodName, parameterClasses);
        } catch (NoSuchMethodException ignored) {
        }
        return null;
    }

    /**
     * 获取指定类的给定名称的字段对象
     * @param cs 类型
     * @param fieldName 字段名称
     * @return 返回指定类的给定名称字段
     * @throws NullPointerException 假如参数为空，则抛出该异常
     * @throws RuntimeException 获取字段失败，则抛出该异常
     */
    public static Field quickGetField(Class<?> cs, String fieldName){
        AssertUtils.isNotNull(cs, "cs parameter must be not null!");
        AssertUtils.isNotNull(fieldName, "fieldName parameter must be not null or empty!");
        try {
            return cs.getField(fieldName.trim());
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取指定类的给定名称的字段对象
     * @param cs 类型
     * @param fieldName 字段名称
     * @return 返回指定类的给定名称字段，假如获取失败，则返回null
     * @throws NullPointerException 假如参数为空，则抛出该异常
     */
    public static Field getField(Class<?> cs, String fieldName){
        AssertUtils.isNotNull(cs, "cs parameter must be not null!");
        AssertUtils.isNotNull(fieldName, "fieldName parameter must be not null or empty!");
        try {
            return cs.getField(fieldName.trim());
        } catch (NoSuchFieldException ignored) {
        }
        return null;
    }
}
